package com.ycl.bookstore.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycl.bookstore.common.Result;
import com.ycl.bookstore.mapper.CouponOrderMapper;
import com.ycl.bookstore.mapper.LimitedTimeCouponMapper;
import com.ycl.bookstore.mapper.UserCouponMapper;
import com.ycl.bookstore.pojo.Coupon;
import com.ycl.bookstore.pojo.CouponOrder;
import com.ycl.bookstore.pojo.LimitedTimeCoupon;
import com.ycl.bookstore.pojo.UserCoupon;
import com.ycl.bookstore.service.CouponService;
import com.ycl.bookstore.mapper.CouponMapper;
import com.ycl.bookstore.utils.MyThreadLocal;
import com.ycl.bookstore.utils.RedisIdWorker;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

import static com.ycl.bookstore.utils.RedisConstants.*;

/**
 *
 */
@Service
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon>
        implements CouponService {

    @Resource
    private CouponMapper couponMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private UserCouponMapper userCouponMapper;

    @Resource
    private LimitedTimeCouponMapper limitedTimeCouponMapper;

    @Resource
    private CouponOrderMapper couponOrderMapper;

    @Override
    @Transactional
    public Result addSignCoupon(Long couponId) {
        // 获取当前用户的id
        Long userId = MyThreadLocal.getUser().getId();
        // 目前优惠券页面list还未查询数据库
        Coupon coupon = couponMapper.selectById(couponId);
        // 得到redis的key
        String hashKey = couponId + "-" + coupon.getCouponType();
        String key = USER_COUPON_KEY + userId;
        // 查询redis中是否存在优惠卷
        Boolean res = stringRedisTemplate.opsForHash().hasKey(key, hashKey);
        if(res){
            return Result.fail("领取失败,你已经领取过了");
        }
        // 向用户优惠卷的表中 添加用户领取的优惠卷
        UserCoupon userCoupon = createUserCouponBySign(coupon, userId, 7);
        int count = userCouponMapper.insert(userCoupon);
        if (count < 1) {
            return Result.fail("领取失败");
        }
        // 创建优惠卷订单
        CouponOrder couponOrder = createSignCouponOrder(coupon, userId);
        System.out.println(couponOrder);
        // 存入到数据库中
        couponOrderMapper.insert(couponOrder);
        // 将对象转为json对象
        String jsonUserCoupon = JSONUtil.toJsonStr(userCoupon);
        stringRedisTemplate.opsForHash().put(key, hashKey, jsonUserCoupon);
        return Result.success();
    }

    /**
     * 获取优惠卷信息
     * @return
     */
    @Override
    public Result getCouponInfo() {
        List<LimitedTimeCoupon> coupon = null;
        Map<String, Object> data = new HashMap<>();
        String couponInfo = stringRedisTemplate.opsForValue().get(COUPON_INFO_KEY);
        if (couponInfo == null) {
            // 得到限时优惠卷的信息
            coupon = limitedTimeCouponMapper.selectList(null);
            // 将java对象转为json对象
            String couponJsonStr = JSONUtil.toJsonStr(coupon);
            // 查询redis是否存在优惠卷信息(防止用户发送两次这个请求)
            // redis 中不存在的话
            stringRedisTemplate.opsForValue().set(COUPON_INFO_KEY, couponJsonStr);
            data.put("couponInfo", coupon);
            return Result.success(data);
        }
        // redis 存在的话
        coupon = JSONUtil.toList(couponInfo, LimitedTimeCoupon.class);
        data.put("couponInfo", coupon);
        return Result.success(data);
    }

    /**
     * 用户抢购限时优惠卷
     *
     * @return
     */
    @Override
    @Transactional
    public Result addLimitCoupon(Long couponId) {
        // 获取用户id
        Long userId = MyThreadLocal.getUser().getId();
        // 查询限时优惠卷信息
        LimitedTimeCoupon limitedTimeCoupon = limitedTimeCouponMapper.selectById(couponId);
        // 判断是否是活动期间
        String message = isActivityTime(limitedTimeCoupon);
        if(!message.equals("ok")){
            return Result.fail(message);
        }
        // 生成key
        String hashKey = couponId + "-" + limitedTimeCoupon.getCouponType();
        String key = USER_COUPON_KEY + userId;
        // 查询redis中是否存在优惠卷(防止用户发了两次请求)
        Boolean res = stringRedisTemplate.opsForHash().hasKey(key, hashKey);
        if(res){
            return Result.success("对不起,你已经领取过了,一人只能领取一张");
        }
        //判断库存是否充足
        if(limitedTimeCoupon.getQuantity()<1){
            //库存不足
            return Result.fail("不好意思,已经被抢空了");
        }
        // 扣除库存
        limitedTimeCoupon.setQuantity(limitedTimeCoupon.getQuantity()-1);
        // 实现一人一单(防止一个用户多张卷)
        LambdaQueryWrapper<LimitedTimeCoupon> wrapper=new LambdaQueryWrapper<>();
        wrapper.gt(LimitedTimeCoupon::getQuantity,0);
        int count = limitedTimeCouponMapper.update(limitedTimeCoupon, wrapper);
        if(count<1){

        }
        // 因为限时优惠卷的信息更新了 因此要删除redis存储的信息
        stringRedisTemplate.delete(COUPON_INFO_KEY);
        // 创建用户优惠卷信息
        UserCoupon userCoupon = createUserCouponByLimit(limitedTimeCoupon, userId, 15);
        // 存入数据库中
        userCouponMapper.insert(userCoupon);
        // 创建优惠卷订单
        CouponOrder limitCouponOrder = createLimitCouponOrder(limitedTimeCoupon, userId);
        couponOrderMapper.insert(limitCouponOrder);
        // 将对象转为json对象
        stringRedisTemplate.opsForHash().put(key,hashKey,JSONUtil.toJsonStr(userCoupon));
        return Result.success();
    }

    @Override
    public Result myCoupon() {
        // 获取用户id
        Long userId = MyThreadLocal.getUser().getId();
        // 获取key
        String key=USER_COUPON_KEY+userId;
        // 向redis中查询用户的优惠卷信息
        Map<Object, Object> userCoupon = stringRedisTemplate.opsForHash().entries(key);
        // 从后端返回前端的数据
        List<UserCoupon> data=new LinkedList<>();
        Set<Object> set = userCoupon.keySet();
        for (Object couponKey : set) {
            UserCoupon coupon = JSONUtil.toBean((String) userCoupon.get(couponKey), UserCoupon.class);
            data.add(coupon);
        }
        return Result.success(data);
    }


    /**
     * 创建用户的限时优惠卷
     * @param limitedTimeCoupon
     * @param userId
     * @param day
     * @return
     */
    private UserCoupon createUserCouponByLimit(LimitedTimeCoupon limitedTimeCoupon, Long userId, int day) {
        UserCoupon userCoupon = new UserCoupon();
        userCoupon.setUserId(userId);
        userCoupon.setCouponId(limitedTimeCoupon.getId());
        userCoupon.setCouponType(limitedTimeCoupon.getCouponType());
        userCoupon.setUsageStatus("未使用");
        // 优惠卷描述
        userCoupon.setDescribe(limitedTimeCoupon.getDetails());
        // 获得现在的时间
        LocalDateTime now = LocalDateTime.now();
        userCoupon.setCouponStartDate(now);
        // 失效时间
        userCoupon.setCouponEddDate(now.plusDays(day));
        // 用户领取优惠卷的时间
        userCoupon.setCreatedAt(now);
        // 折扣金额
        userCoupon.setDiscountAmount(limitedTimeCoupon.getDiscountAmount());
        // 最低消费金额
        userCoupon.setMinimumAmount(limitedTimeCoupon.getMinimumAmount());
        userCoupon.setUpdatedAt(limitedTimeCoupon.getUpdatedAt());
        return userCoupon;
    }

    /**
     * 创建用户优惠卷对象(签到优惠卷)
     *
     * @param coupon
     * @return
     */
    public UserCoupon createUserCouponBySign(Coupon coupon, Long userId, int effectiveTime) {
        UserCoupon userCoupon = new UserCoupon();
        userCoupon.setUserId(userId);
        userCoupon.setCouponId(coupon.getId());
        userCoupon.setCouponType(coupon.getCouponType());
        userCoupon.setUsageStatus("未使用");
        userCoupon.setUsageDate(null);
        // 优惠卷的描述
        userCoupon.setDescribe(coupon.getDetails());
        // 获取当前时间
        LocalDateTime startTime = LocalDateTime.now();
        // 获取有效时间天后的时间
        LocalDateTime eddTime = startTime.plusDays(effectiveTime);
        userCoupon.setCouponStartDate(startTime);
        userCoupon.setCouponEddDate(eddTime);
        // 用户领取优惠卷的日期
        userCoupon.setCreatedAt(startTime);
        userCoupon.setUpdatedAt(coupon.getUpdatedAt());
        // 折扣金额
        userCoupon.setDiscountAmount(coupon.getDiscountAmount());
        // 最小消费金额
        userCoupon.setMinimumAmount(coupon.getMinimumAmount());
        return userCoupon;
    }

    /**
     * 生成优惠卷订单(签到优惠卷)
     * @param coupon
     * @param userId
     * @return
     */
    private CouponOrder createSignCouponOrder(Coupon coupon,Long userId) {
        CouponOrder couponOrder = new CouponOrder();
        // 生成唯一优惠卷订单id
        long orderId = new RedisIdWorker(stringRedisTemplate).nextId(COUPON_ORDER_KEY);
        couponOrder.setOrderId(orderId);
        couponOrder.setCouponId(coupon.getId());
        couponOrder.setUserId(userId);
        couponOrder.setCouponType(0);
        couponOrder.setDiscountAmount(coupon.getDiscountAmount());
        couponOrder.setMinimumAmount(coupon.getMinimumAmount());
        couponOrder.setCreatedAt(LocalDateTime.now());
            return couponOrder;
    }


    /**
     * 判断是否是活动期间
     * @param limitedTimeCoupon
     * @return
     */
     public String isActivityTime(LimitedTimeCoupon limitedTimeCoupon){
         // 获取当前时间
         LocalDateTime now = LocalDateTime.now();
         // 判断活动是否开始了
        if(limitedTimeCoupon.getActivityStartDate().isAfter(now)){
            // 尚未开始
            return "活动还未开始";
        }
        if(limitedTimeCoupon.getActivityEddDate().isBefore(now)){
            // 已经结束
            return "活动已经结束";
        }
        // ok 表示在活动期间
        return "ok";
     }

    /**
     * 创建限时优惠卷订单
     * @return
     */
    private CouponOrder createLimitCouponOrder(LimitedTimeCoupon limitedTimeCoupon,Long userId){
        CouponOrder couponOrder = new CouponOrder();
        // 生成唯一优惠卷订单id
        long orderId = new RedisIdWorker(stringRedisTemplate).nextId(COUPON_ORDER_KEY);
        couponOrder.setOrderId(orderId);
        couponOrder.setUserId(userId);
        couponOrder.setCouponId(limitedTimeCoupon.getId());
        couponOrder.setCouponType(limitedTimeCoupon.getCouponType());
        couponOrder.setDiscountAmount(limitedTimeCoupon.getDiscountAmount());
        couponOrder.setMinimumAmount(limitedTimeCoupon.getMinimumAmount());
        couponOrder.setCreatedAt(LocalDateTime.now());
        return couponOrder;
    }
}




